package com.goodwill.androidtest.stream;

import android.os.Build;

import androidx.annotation.RequiresApi;

import com.goodwill.androidtest.R;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 外部迭代和内部迭代(聚合操作)都是对集合的迭代，但是在机制上还是有一定的差异：
 * <p>
 * 迭代器提供next()、hasNext()等方法，开发者可以自行控制对元素的处理，以及处理方式，但是只能顺序处理；
 * stream()方法返回的数据集无next()等方法，开发者无法控制对元素的迭代，迭代方式是系统内部实现的，同时系统内的迭代也不一定是顺序的，还可以并行，
 * 如parallelStream()方法。并行的方式在一些情况下，可以大幅提升处理的效率。
 */
public class StreamTest {
    static List<Student> list = new ArrayList<>();

    public static void main(String[] args) {
        fillStudents();
//        filterGirlByIterator(list);
//        filterGirlByStream(list);
//        createStream();
//        streamConcat();
//          streamAnyMatch();
//        streamFindAny();
//          streamToMap();
//          streamMapGroupBy();
        testStreamCollectors();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void streamConcat() {
        Stream intArr = Stream.of(1, 2, 3);
        Stream strArr = Stream.of("guo", "xiao", "jun");
        Stream.concat(intArr, strArr).forEach(t -> System.out.println(t));
    }

    private static void fillStudents() {
        Student stuA = new Student(1, "A", "M", 184);
        Student stuB = new Student(2, "B", "G", 163);
        Student stuC = new Student(3, "C", "M", 175);
        Student stuD = new Student(4, "D", "G", 158);
        Student stuE = new Student(5, "E", "M", 170);
        list.add(stuA);
        list.add(stuB);
        list.add(stuC);
        list.add(stuD);
        list.add(stuE);
    }

    private static void filterGirlByIterator(List<Student> list) {
        Iterator<Student> iterator = list.iterator();
        while (iterator.hasNext()) {
            Student student = iterator.next();
            if ("G".equals(student.getSex())) {
                System.out.println(student.toString());
            }
        }
        /**
         * 打印输出:
         * Student{no=2, name='B', sex='G', height=163.0}
         * Student{no=4, name='D', sex='G', height=158.0}
         */
    }

    //在Java 8中，我们可以采用聚合操作

    /**
     * Stream的操作分类
     * 刚才提到的Stream的操作有Intermediate、Terminal和Short-circuiting：
     * <p>
     * Intermediate：map(mapToInt,flatMap等)、filter、distinct、sorted、peek、skip、parallel、sequential、unordered
     * <p>
     * Terminal：forEach、forEachOrdered、toArray、reduce、collect、min、max、count、iterator
     * <p>
     * Short-circuiting：anyMatch、allMatch、noneMatch、findFirst、findAny、limit
     *
     * @param list
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void filterGirlByStream(List<Student> list) {
        list.stream()
                .filter(stu -> "G".equals(stu.getSex()))
                .forEach(stu -> System.out.println(stu.toString()));
        /**
         * 打印输出:
         * Student{no=2, name='B', sex='G', height=163.0}
         * Student{no=4, name='D', sex='G', height=158.0}
         */
        /**
         * 惰性求值和及早求值方法
         * 像filter这样只描述Stream, 最终不产生新集合的方法叫作惰性求值方法；
         * 而像count这样最终会从Stream产生值的方法叫作及早求值方法。
         */
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void createStream() {
        //方式一: Stream接口的静态工厂方法(注意：Java8里接口可以带静态方法)
        Stream<Integer> stream1 = Stream.of(2, 1, 3);
        //方式二: Collection接口和数组的默认方法
        Stream<Student> stream2_1 = list.stream();
        int[] intArray = {1, 4, 5};
        IntStream stream2_2 = Arrays.stream(intArray);
        /**
         * 其他方式:
         *  Random.ints()
         *  BitSet.stream()
         *  Pattern.splitAsStream(java.lang.CharSequence)
         *  JarFile.stream()
         */
//        IntStream intStrem = Random.ints();
//        IntStream stream = BitSet.stream();
//        Stream<String> stringStream = Pattern.splitAsStream(",");
//        Stream<JarEntry> jarEntryStream = JarFile.stream();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void streamAnyMatch() {
        boolean isMatch = Stream.of(23, 54, 67, 89, 20)
                .anyMatch(num -> num > 60);
        System.out.println(isMatch);
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void streamFindAny() {
        Optional<Integer> optionalInteger = Stream.of(23, 54, 67, 89, 20)
                .findAny()
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) {
                        return integer > 80;
                    }
                });
        System.out.println("integer:" + optionalInteger);
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void streamToMap() {
        Map<Integer, String> collectMap = list.stream().collect(Collectors.toMap(Student::getNo, Student::getName));
        Map<String, String> collect = Stream.of(Locale.getAvailableLocales())
                .collect(Collectors.toConcurrentMap(Locale::getDisplayLanguage,
                        l -> l.getDisplayLanguage(),
                        (exitingValue, newValue) -> exitingValue));
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void streamMapGroupBy() {
        Map<String, List<Locale>> collect = Stream.of(Locale.getAvailableLocales()).collect(Collectors.groupingBy(Locale::getCountry));

    }

    private static void testStreamCollectors() {
     testStreamCollectorJoining();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void testStreamCollectorJoining() {
        String collect = Stream.of("1", "2", "3", "4", "5")
                .collect(Collectors.joining(",", "[", "]"));
        System.out.println(collect);
    }

}
